package com.gadgets.cm01.auth.advisor.impl;

import com.gadgets.cm01.user.pojo.User;
import com.gadgets.framework.advisor.IRoleAuthCheckProcessor;
import com.gadgets.framework.annotation.RoleAuthCheck;
import com.gadgets.framework.common.constant.GadgetsConstant;
import com.gadgets.framework.common.util.CacheUtils;
import com.gadgets.framework.common.util.RedisUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.HashMap;

/**
 * @author UncleXiu
 * @version V1.0.0
 * @data 2020-09-17
 */
@Component
public class RoleAuthCheckInterceptor extends HandlerInterceptorAdapter {

    public RoleAuthCheckInterceptor(CacheUtils cacheUtils, RedisUtil redisUtil) {
        this.cacheUtils = cacheUtils;
        this.redisUtil = redisUtil;
    }

    private CacheUtils cacheUtils;

    private RedisUtil redisUtil;

    private static final Logger logger = LoggerFactory.getLogger(RoleAuthCheckInterceptor.class);

    private static final HashMap<Class<? extends IRoleAuthCheckProcessor>, IRoleAuthCheckProcessor> PROCESSOR_LIST = new HashMap<>();

    /**
     * This implementation always returns {@code true}.
     *
     * @param request  请求对象
     * @param response 应答对象
     * @param handler  目标方法
     */
    @SuppressWarnings("ConstantConditions")
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (GadgetsConstant.NUMBER_CONSTANT.STR_NUMBER_1.equals(cacheUtils.getSysParamCache(GadgetsConstant.CM01_SYS_PARAM_CODE.CM01_AUTHCHECK))) {
            if (null != request && handler instanceof HandlerMethod) {
                Method targetMethod = ((HandlerMethod) handler).getMethod();
                Class<?> targetClass = ((HandlerMethod) handler).getMethod().getDeclaringClass();
                RoleAuthCheck check = ((HandlerMethod) handler).getMethodAnnotation(RoleAuthCheck.class);
                if (null != check) {
                    logger.debug("方法{}需要权限验证", targetMethod.getName());
                    // 校验用户权限
                    String sessionId = request.getParameter(GadgetsConstant.USER_SESSION_ID_KEY);
                    if (check.ifLogin()) {
                        // 校验是否登录
                        if (null == cacheUtils.getUserSessionCache(sessionId)) {
                            logger.error("用户未登陆，方法{}.{}校验登陆身份，无法访问", targetClass.getName(), targetMethod.getName());
                            response.setStatus(399);
                            return false;
                        }
                    }
                    if (check.userType().length > 0) {
                        // 校验用户类型
                        HashMap<String,Object> logicCache = cacheUtils.getUserSessionCache(sessionId);
                        User user = (User) logicCache.get(GadgetsConstant.SESSION_CACHE_KEY.USER_INFO);
                        for (String allowType : check.userType()) {
                            if(allowType.equals(String.valueOf(user.getUserType()))) {
                                return true;
                            }
                        }
                        logger.error("用户类型不匹配，方法{}.{}无法访问", targetClass.getName(), targetMethod.getName());
                        response.setStatus(599);
                        return false;
                    }
                    if (check.authCheckProcess().length > 0) {
                        // 执行校验器
                        for (Class<? extends IRoleAuthCheckProcessor> aClass : check.authCheckProcess()) {
                            PROCESSOR_LIST.get(aClass).excuteCheck(null);
                        }
                    }
                } else {
                    logger.debug("方法{}无需权限验证", targetMethod.getName());
                }
            } else {
                logger.debug("本次调用无需权限验证");
            }
        } else {
            logger.info("登录校验开关已关闭，无需校验登录状态");
        }
        return true;
    }

    /**
     * 注册权限校验器
     *
     * @param processor 校验器
     */
    public static void registryCheckProcess(IRoleAuthCheckProcessor processor) {
        PROCESSOR_LIST.put(processor.getClass(), processor);
    }

}
